opc = [];

opc[0] = function nopt() {;};
opc[2] = function iconst_m1() { currentFrame.operandStack.push(-1); };
opc[3] = function iconst_0() { 
	if(debugMode == 1) 
		alert("iconst_0");
	currentFrame.operandStack.push(0); };
opc[4] = function iconst_1() { 
	if(debugMode == 1) 
		alert("iconst_1");
	currentFrame.operandStack.push(1); };
opc[5] = function iconst_2() { 
	if(debugMode == 1) 
		alert("iconst_2");
	currentFrame.operandStack.push(2); };
opc[6] = function iconst_3() { 
	if(debugMode == 1) 
		alert("iconst_3");
	currentFrame.operandStack.push(3); };
opc[7] = function iconst_4() { 
	if(debugMode == 1) 
		alert("iconst_4");
	currentFrame.operandStack.push(4); };
opc[8] = function iconst_5() { 
	if(debugMode == 1) 
		alert("iconst_5");
	currentFrame.operandStack.push(5); };

opc[16] = function bipush() { 
	if(debugMode == 1) 
		alert("bipush");
	pc++;
	tmpByte = currentFrame.method.attributes[0].code[pc];
	currentFrame.operandStack.push(tmpByte); 
};

opc[18] = function ldc() {
	if(debugMode == 1) 
		alert("ldc");
	pc++;
	index = currentFrame.method.attributes[0].code[pc];
	stringIndex = mainclass.constant_pool[index].string_index;
	returnString = getStringFromConstantId(stringIndex);
	currentFrame.operandStack.push(returnString);
 };

opc[21] = function iload() { 
	if(debugMode == 1) 
		alert("iload");
	pc++;
	index = currentFrame.method.attributes[0].code[pc];
	currentFrame.operandStack.push(currentFrame.localVariables[index]); 
};

opc[26] = function iload_0() { 
	if(debugMode == 1) 
		alert("iload_0");
	currentFrame.operandStack.push(currentFrame.localVariables[0]); }
opc[27] = function iload_1() { 
	if(debugMode == 1) 
		alert("iload_1");
	currentFrame.operandStack.push(currentFrame.localVariables[1]); }
opc[28] = function iload_2() { 
	if(debugMode == 1) 
		alert("iload_2");
	currentFrame.operandStack.push(currentFrame.localVariables[2]); }
opc[29] = function iload_3() { 
	if(debugMode == 1) 
		alert("iload_3");
	currentFrame.operandStack.push(currentFrame.localVariables[3]); }

opc[54] = function istore() { 
	if(debugMode == 1) 
		alert("istore");
	pc++;
	index = currentFrame.method.attributes[0].code[pc];
	currentFrame.localVariables[index] = currentFrame.operandStack.pop();
};
opc[59] = function istore_0() { 
	if(debugMode == 1) 
		alert("istore_0");
	currentFrame.localVariables[0] = currentFrame.operandStack.pop();};
opc[60] = function istore_1() { 
	if(debugMode == 1) 
		alert("istore_1");
	currentFrame.localVariables[1] = currentFrame.operandStack.pop();};
opc[61] = function istore_2() { 
	if(debugMode == 1) 
		alert("istore_2");
	currentFrame.localVariables[2] = currentFrame.operandStack.pop();};
opc[62] = function istore_3() { 
	if(debugMode == 1) 
		alert("istore_3");
	currentFrame.localVariables[3] = currentFrame.operandStack.pop();};

opc[96] = function iadd() { 
	if(debugMode == 1) 
		alert("iadd");
	currentFrame.operandStack.push(currentFrame.operandStack.pop()+currentFrame.operandStack.pop());
};

opc[100] = function isub() { 
	if(debugMode == 1) 
		alert("isub");
	currentFrame.operandStack.push(-currentFrame.operandStack.pop()+currentFrame.operandStack.pop());
};

opc[104] = function imul() { 
	currentFrame.operandStack.push(currentFrame.operandStack.pop()*currentFrame.operandStack.pop());
};

opc[108] = function idiv() { 
	a = currentFrame.operandStack.pop();
	b = currentFrame.operandStack.pop();
	currentFrame.operandStack.push(a/b);
};

opc[172] = function ireturn() { 
	if(debugMode == 2) 
		alert("ireturn");
	if(callStack.length >= 2) {
		callStack[callStack.length-2].operandStack.push(currentFrame.operandStack.pop());
		callStack.pop();
		currentFrame = callStack[callStack.length-1];
		pc = currentFrame.currentPc;
		//alert("returned_pc:"+pc);
		this.codelength = currentFrame.method.attributes[0].code_length;
		//alert("return current pc: " + pc);
		//alert("return current method code len: " + currentFrame.method.attributes[0].code_length);
	} else {
		alert("callStack length less than 2, 172");
		//returnValue = null;
	}
};

opc[177] = function returnNull() { 
	if(callStack.length >= 2) {
		callStack.pop();
		currentFrame = callStack[callStack.length-1];
		pc = currentFrame.currentPc;
	} else {
		alert("callStack length less than 2, 177");
	//alert("return");
	}
};

opc[178] = function getstatic() {
	if(debugMode == 1) 
		alert("getstatic");
	pc++;
	indexbyte1 = currentFrame.method.attributes[0].code[pc];
	pc++;
	indexbyte2 = currentFrame.method.attributes[0].code[pc];
	index = (indexbyte1 << 8) | indexbyte2;

	if(mainclass.constant_pool[index].tag == 20) { //this number means it has been visited before
		currentFrame.operandStack.push(mainclass.constant_pool[index].content);
	} else {

	}
};

opc[179] = function putstatic() { 
	if(debugMode == 1) 
		alert("putstatic");
	pc++;
	indexbyte1 = currentFrame.method.attributes[0].code[pc];
	pc++;
	indexbyte2 = currentFrame.method.attributes[0].code[pc];
	index = (indexbyte1 << 8) | indexbyte2;
	mainclass.constant_pool[index].tag = 20; //this number means it has been analyzed
	mainclass.constant_pool[index].content = currentFrame.operandStack.pop();
};

opc[184] = function invokestatic() { 
	if(debugMode == 1)
		alert("invokestatic");
	pc++;
	indexbyte1 = currentFrame.method.attributes[0].code[pc];
	pc++;
	indexbyte2 = currentFrame.method.attributes[0].code[pc];
	index = (indexbyte1 << 8) | indexbyte2;
	currentFrame.currentPc = pc; //memorize the next pc position
	if(debugMode == 1)
		alert("currentPc:"+currentFrame.currentPc);

	nextFrame = new callFrame();

	//ignore the class part, we have only mainclass here.
	nameTypeIndex = mainclass.constant_pool[index].name_and_type_index;
	nameIndex = mainclass.constant_pool[nameTypeIndex].name_index;
	descriptor_index = mainclass.constant_pool[nameTypeIndex].descriptor_index;
	if(debugMode == 1)
		alert("method: " + descriptor_index);
	nextMethod = findMethodByNameIndex(nameIndex);
	nextFrame.method = nextMethod;
	inputNum = findDescriptorInputNum(descriptor_index);
	//alert("inputNum: " + inputNum);
	for(i = inputNum-1; i >= 0; i--) {
		nextFrame.localVariables[i] = currentFrame.operandStack.pop();
	}
	
	callStack.push(nextFrame);
	currentFrame = callStack[callStack.length-1];
	//alert("currentFrame LocalVariables: " + currentFrame.localVariables);
	//alert("second pc: " +callStack[callStack.length-2].currentPc);
	currentFrame.execute();

};

findDescriptorInputNum = function(dIndex) {
	descriptorString = mainclass.constant_pool[dIndex].bytes;
	//alert("descriptorString: " + descriptorString);
	num = 0;
	for(i = 1; i < descriptorString.length; i++) {
		if(descriptorString[i] != 41) { //41 == ')'
			num++;
		} else {
			return num;
		}
	}
}

findMethodByNameIndex = function(nameIndex) {
	//alert("in findMethodByNameIndex");
	for(i in mainclass.methods) {
		//alert("methods: "+i);
		if(mainclass.methods[i].name_index == nameIndex) {
			//alert("find "+name);
			//execute the found method, construct a new frame, and push it into the callStack
			return mainclass.methods[i];
		}
	}
}


//fake native methods, just for demo
opc[182] = function invokevirtual() { 
	if(debugMode == 1)
		alert("invokevirtual");
	pc++;
	indexbyte1 = currentFrame.method.attributes[0].code[pc];
	pc++;
	indexbyte2 = currentFrame.method.attributes[0].code[pc];
	index = (indexbyte1 << 8) | indexbyte2;
	
	nameTypeIndex = mainclass.constant_pool[index].name_and_type_index;
	nameIndex = mainclass.constant_pool[nameTypeIndex].name_index;
	typeIndex = mainclass.constant_pool[nameTypeIndex].descriptor_index;
	if(getStringFromConstantId(nameIndex) == "println") {
		alert("print: "+currentFrame.operandStack.pop());
	}

};

//get the strings from constant pool
getStringFromConstantId = function(id) {
	stringValue = "";
	for(everyChar in mainclass.constant_pool[id].bytes) {
		charValue = String.fromCharCode(mainclass.constant_pool[id].bytes[everyChar]);
		stringValue += charValue;
	}
		//alert(stringValue);
	return stringValue;
}

